﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.Web.SessionState;
using System.IO;
using Pixysoft.Framework.Configurations;
using Pixysoft.Framework.Remoting.Core;
using Pixysoft.Framework.Security;
using System.Reflection;
using Pixysoft.Framework.Remoting.Controller;

namespace Pixysoft.Framework.Remoting
{
    class RemoteHandler : IHttpHandler, IReadOnlySessionState
    {
        public bool IsReusable
        {
            get
            {
                return true;
            }
        }

        public void ProcessRequest(HttpContext context)
        {
            IXmlNode request = GetRequestContent(context);

            if (request == null)
            {
                ProcessEmptyRequest(context);

                return;
            }

            string token = request.Properties[CommandController.default_attribute_token];

            string command = request.Properties[CommandController.default_attribute_command];

            switch (Pixysoft.EnumCoder.ToEnum<RemoteCommand>(command))
            {
                case RemoteCommand.Login:
                    {
                        ProcessLogin(context, request, token, command);

                        return;
                    }
                case RemoteCommand.Logout:
                    {
                        SSoManager.Instance.TokenLogout(token);

                        EndRequest(context, CommandController.Instance.CreateSimpleResponse(token, command, true, null));

                        return;
                    }
                case RemoteCommand.RemoteCall:
                    {
                        ProcessRemoteCall(context, request, token, command);

                        return;
                    }
                case RemoteCommand.DynamicCall:
                    {
                        ProcessRemoteDynamicCall(context, request, token, command);

                        return;
                    }

                case RemoteCommand.Unknown:
                default:
                    {
                        ProcessUnknownCommand(context, request, token, command);

                        return;
                    }
            }
        }

        private void ProcessEmptyRequest(HttpContext context)
        {
            EndRequest(context, "copyright 2010 by pixysoft.net");

            return;
        }

        private void ProcessUnknownCommand(HttpContext context, IXmlNode request, string token, string command)
        {
            EndRequest(context, CommandController.Instance.CreateSimpleResponse(token, command, false, "unknown command."));

            return;
        }

        private void ProcessRemoteCall(HttpContext context, IXmlNode request, string token, string command)
        {
            if (!SSoManager.Instance.TokenValidate(token))
            {
                EndRequest(context, CommandController.Instance.CreateSimpleResponse(token, command, false, "authentification fail."));

                return;
            }

            SSoManager.Instance.TokenExtend(token);

            string base64content = request.Text;

            if (string.IsNullOrEmpty(base64content))
            {
                EndRequest(context, CommandController.Instance.CreateSimpleResponse(token, command, false, "unknown request content."));

                return;
            }

            IXmlNode response = null;

            try
            {
                string encryptcontent = Pixysoft.Security.Base64.Decript(base64content);

                string compresscontent = Pixysoft.Security.DES.Decrypt(encryptcontent, StringHelper.global_framework_id);

                string content = Pixysoft.IO.Compressor.Instance.DeCompress(compresscontent);

                string responsevalue = ReflectionController.Instance.GetSerializeRemoteCallResult(content);

                //10-04-20 有可能返回值就是null

                if (string.IsNullOrEmpty(responsevalue))
                {
                    response = CommandController.Instance.CreateResponse(token, command, true);
                }
                else
                {
                    compresscontent = Pixysoft.IO.Compressor.Instance.Compress(responsevalue);

                    encryptcontent = Pixysoft.Security.DES.Encrypt(compresscontent, StringHelper.global_framework_id);

                    base64content = Pixysoft.Security.Base64.Encript(encryptcontent);

                    response = CommandController.Instance.CreateResponse(token, command, true, base64content);
                }
            }
            catch (Exception ex)
            {
                LoggerHelper.Fatal(ex);

                response = CommandController.Instance.CreateResponse(token, command, false, ex.ToString());
            }

            EndRequest(context, response.Serialize());

            return;
        }

        private void ProcessRemoteDynamicCall(HttpContext context, IXmlNode request, string token, string command)
        {
            if (!SSoManager.Instance.TokenValidate(token))
            {
                EndRequest(context, CommandController.Instance.CreateSimpleResponse(token, command, false, "authentification fail."));

                return;
            }

            SSoManager.Instance.TokenExtend(token);

            string compresscontent = request.Text;

            if (string.IsNullOrEmpty(compresscontent))
            {
                EndRequest(context, CommandController.Instance.CreateSimpleResponse(token, command, false, "unknown request content."));

                return;
            }

            IXmlNode response = null;

            try
            {
                string content = Pixysoft.IO.Compressor.Instance.DeCompress(compresscontent);

                //2010-10-06 增加了方法映射

                MethodStructure methodStructure = XmlManager.MethodStructureDeserialize(content);

                string assemblyName = methodStructure.AssemblyName;

                string typeName = methodStructure.TypeName;

                RemotingAssemblyMapping mapping = null;

                mapping = SettingHelper.Mappings.SearchMapping(methodStructure.AssemblyName, methodStructure.TypeName);

                if (mapping != null)
                {
                    assemblyName = mapping.MappingAssemblyName;

                    typeName = mapping.MappingTypeName;
                }
                else
                {
                    mapping = SettingHelper.Mappings.SearchMapping(methodStructure.AssemblyName);

                    if (mapping != null)
                    {
                        assemblyName = mapping.MappingAssemblyName;

                        typeName = typeName.Replace(mapping.AssemblyName, mapping.MappingAssemblyName);
                    }
                }

                object returnvalue = XmlManager.MethodDeserialize(assemblyName, typeName, content);

                //10-04-20 有可能返回值就是null

                if (returnvalue == null)
                {
                    response = CommandController.Instance.CreateResponse(token, command, true);
                }
                else
                {
                    string responsevalue = XmlManager.DynamicSerialize(returnvalue).Serialize();

                    compresscontent = Pixysoft.IO.Compressor.Instance.Compress(responsevalue);

                    response = CommandController.Instance.CreateResponse(token, command, true, compresscontent);
                }
            }
            catch (Exception ex)
            {
                LoggerHelper.Fatal(ex);

                response = CommandController.Instance.CreateResponse(token, command, false, ex.ToString());
            }

            EndRequest(context, response.Serialize());

            return;
        }

        private void ProcessLogin(HttpContext context, IXmlNode request, string token, string command)
        {
            if (!request.Node.Contains(CommandController.default_element_username) ||
                !request.Node.Contains(CommandController.default_element_md5password))
            {
                EndRequest(context, CommandController.Instance.CreateSimpleResponse(
                   token, command, false, "missing username or password."));

                return;
            }

            string username = request.Node[CommandController.default_element_username].Text;
            string md5password = request.Node[CommandController.default_element_md5password].Text;

            try
            {
                token = SSoManager.Instance.TokenLogin(username, md5password);
            }
            catch (Exception ex)
            {
                LoggerHelper.Fatal(ex);

                EndRequest(context, CommandController.Instance.CreateSimpleResponse(
                        token, command, false, ex.ToString()));
                return;
            }

            if (string.IsNullOrEmpty(token))
            {
                EndRequest(context, CommandController.Instance.CreateSimpleResponse(
                      token, command, false, "login fail, please check username/password"));

                return;
            }

            EndRequest(context, CommandController.Instance.CreateSimpleResponse(
                  token, command, true, token));

            return;
        }



        private IXmlNode GetRequestContent(HttpContext context)
        {
            try
            {
                StreamReader reader = new StreamReader(context.Request.InputStream);

                string request = reader.ReadToEnd();

                if (string.IsNullOrEmpty(request))
                    return null;

                LoggerHelper.Debug("WEB.REQUEST:" + request);

                IXmlNode node = XmlManager.Deserialize(request);

                return node;
            }
            catch (Exception ex)
            {
                LoggerHelper.Error(ex.ToString());

                return null;
            }
        }

        protected void EndRequest(HttpContext context, string response)
        {
            LoggerHelper.Debug("WEB.RESPONSE:" + response);

            EndRequest(context, Pixysoft.StringCoder.StringToByte(response));
        }

        protected void EndRequest(HttpContext context, byte[] response)
        {
            if (response == null)
                response = new byte[] { 0 };

            context.Response.Clear();

            context.Response.ContentType = "application/octet-stream";

            BinaryWriter writer = new BinaryWriter(context.Response.OutputStream);

            writer.Write(response);

            writer.Flush();

            writer.Close();

            context.Response.End();
        }
    }
}
